
#include "Computer.h"
#include "Player.h"
#include "Card.h"
#include <iostream>
#include <vector>
#include <string>
#include "Group.h"
#include "Run.h"
#include "Set.cpp"
#include "SetIter.cpp"
#include "Meld.h"

using std::ostream;
using std::cout;
using std::vector;
using std::string;
Computer::Computer(string str1):Player(str1,"Computer"),valGrid(),handReadFirst(false){}

ostream & Computer::display(ostream &os) const
{
  os<<"Type: "<<type<<" "<<"Name: "<<name<<std::endl;
  return os;
}

bool Computer::move(vector<Meld*> &tb2)
{
  //call first move until find the sequence
  handBuffer=hand;
  if(firstMoveDone==false)
  {/*
cout<<"input some int\n";
  int b;
  std:: cin>>b;
*/
    return firstMove(tb2);
     
  }
 
  else
    {
      // cout<<"input some int\n";
      // int b;
      // std:: cin>>b;

      readInGrid();
      cout<<"computer "<<this->name<<" take a move"<<std::endl;
      //      displayHand(cout);
      cout<<endl;
      displayTableBuffer(cout,tb2);

      
      return ( lookForRun(tb2) || addToTable(tb2)||lookForSet(tb2));

    }
  return 1;
}

bool Computer::addToTable(vector <Meld*>& tb2)
{

  bool added=false;
  Meld *mptr;
  Set<Card> tempCardSet;
  // SetIter<Card> tempIter;
  handBuffer=hand;

  for(int i=0;i<tb2.size() && added==false;i++)
    {
      //     cout<<" \nin meld "<<i<<" ";
      mptr=(tb2.at(i));
      tempCardSet=mptr->getValidCards();
      if(tempCardSet.size()>0)
	{
	  SetIter<Card> tempIter(tempCardSet); 
	  while(tempIter.hasNext())
	    {
	      Card tempCard=tempIter.next();
	      //    cout<<"Card in valid set"<<tempCard<<" ";
	      //search within hand for valid cards
	      bool cardFound=false;
	      for(vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==false;hiter++)
		{

		  if( (*hiter)== tempCard)
		    {
		      cardFound=true;
		      //addToMeld

		      int row=tempCard.face-1;
		      int col=tempCard.suit;
		      valGrid[row][col]--;
		      handBuffer.erase(hiter);//erase from buffer
		      mptr->add(tempCard);
		      cout<<"Computer add card "<<tempCard<<" to meld "<<(i+1)<<" on table\n";
		      added=true;
		      return added;

		    }//end if

		}//end for(vector...)
	    }//end while
	}//end if tempCardSet...

    }
  // if(added==0)
  // {cout<<"cannot add to current meld to table because no proper card exist in hand";}

  return added;
}//end addToTable
 

bool Computer::readInGrid()
{
  // std::cout<<"reading in grid...";  
  for(int i=0;i<13;i++)
    for(int j=0;j<4;j++)
      { valGrid[i][j]=0;}



  for(int i=0;i<hand.size();i++)
    {
      Card & temp=hand.at(i);
      //      cout<<temp<<' ';
      int tempS=temp.suit,tempF=temp.face;
      valGrid[tempF-1][tempS]++;
    }

  /* cout<<"\n D C H S\n";
for(int i=0;i<13;i++)
  {
    cout<<(i+1)<<' ';
    for(int j=0;j<4;j++)
      { cout<<valGrid[i][j]<< ' ';}

    cout<<'\n';
  }

 handReadFirst=1;*/  
  return 1;

}

bool Computer::lookForSet(vector<Meld*> &tb2)
{
  bool setExist=false;
  //  cout<<"Inside loop for set\n";
  int setCount=0,i=0,j=0;
  Set<Card> tempCardSet;
  int multi0,multi1,multi2,multi3,multi4,multi;

  /*
  displayHand(cout);
 cout<<"valGrid: for testing in computer.cpp lookForSet method "<<std::endl;//display valGrid here
  for(int i=0;i<13;i++)
    {
    cout<<(i+1)<<' ';
    for(int j=0;j<4;j++)
      { cout<<valGrid[i][j]<< ' ';}

    cout<<'\n';
    }
*/
  for(i=0;i<13 && setExist==false;i++)//for each of face value 
    {
      // for(j=0;j<=1 && setExist==false;j++)//check diamond to spade
      //	{
	  //if find one run give the starting index
	  //and total number of cards in the run
           multi0=(valGrid[i][1])*(valGrid[i][2])*(valGrid[i][3]);
           multi1=(valGrid[i][0])*(valGrid[i][2])*(valGrid[i][3]);
	   multi2=(valGrid[i][0])*(valGrid[i][1])*(valGrid[i][3]);
	   multi3=(valGrid[i][0])*(valGrid[i][1])*(valGrid[i][2]);
	   
	   multi4=multi0*multi1*multi2*multi3;
	   // cout<<"multi4="<<multi4<<endl;

	   multi=multi0+multi1+multi2+multi3;
	   if(multi<=0)//right now
	     {
	       //  cout<<"set don't exist in look for set method";
	       return setExist;
	     }
	 else if(multi4!=0)//if 4 in set
	    {
	      setExist=true;
	      setCount=4;
	      //	      cout<<"in look for set face : "<<i+1<<endl;
	      // cout<<"int look for set Set found";
	      //add 4 cards to the set
	    }
	  else if(multi!=0)//if 3 in set
	    {
	      setExist=true;
	      setCount=3;
	      // cout<<"3 in a set face :"<<i+1<<endl;
	    }

	  //	}//end for j
	}//end for i

  i--;
  
  handBuffer=hand;
  if(setCount==4)
    {
      for(int c1=0;c1<setCount;c1++)
	{
	  Card cardTemp(i+1,c1);
	  bool cardFound=false;

	  for (vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==0;hiter++)
	    {
	      if((*hiter)==cardTemp)
		{
		  cardFound=1;
		  // cout<<"\nerasing from handBuffer..."<<(*hiter)<<std::endl;
		  handBuffer.erase(hiter);
		  //add to set here
		  tempCardSet.add(cardTemp);

		  valGrid[i][c1]--;//delete from grid

		}//end if

	    }//end searching in handbuffer (for loop 


	}//end for c1

    }//end for setCount==4

 else if(multi0!=0 &&setCount==3)//have card in 1 2 3 position
    {
          for(int c1=0;c1<=setCount;c1++)
	{
	  Card cardTemp(i+1,c1);
	  bool cardFound=false;

	  for (vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==0;hiter++)
	    {
	      if(c1!=0 && (*hiter)==cardTemp)//dont have card in 0 position
		{
		  cardFound=1;
		  // cout<<"\nerasing from handBuffer..."<<(*hiter)<<std::endl;
		  handBuffer.erase(hiter);
		  //add to set here
		  tempCardSet.add(cardTemp);

		  valGrid[i][c1]--;//delete from grid

		}//end if

	    }//end searching in handbuffer (for loop 


	}//end for c1
 

    }//end if multi0!=0

 else if(multi1!=0 &&setCount==3)//have card in 0 2 3 position
    {
          for(int c1=0;c1<=setCount;c1++)
	{
	  Card cardTemp(i+1,c1);
	  bool cardFound=false;

	  for (vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==0;hiter++)
	    {
	      if(c1!=1 && (*hiter)==cardTemp)//dont have card in 0 position
		{
		  cardFound=1;
		  // cout<<"\nerasing from handBuffer..."<<(*hiter)<<std::endl;
		  handBuffer.erase(hiter);
		  //add to set here
		  tempCardSet.add(cardTemp);

		  valGrid[i][c1]--;//delete from grid

		}//end if

	    }//end searching in handbuffer (for loop 


	}//end for c1
 

    }//end if multi1!=0

 else if(multi2!=0 &&setCount==3)//have card in 0 2 3 position
    {
          for(int c1=0;c1<=setCount;c1++)
	{
	  Card cardTemp(i+1,c1);
	  bool cardFound=false;

	  for (vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==0;hiter++)
	    {
	      if(c1!=2 && (*hiter)==cardTemp)//dont have card in 0 position
		{
		  cardFound=1;
		  // cout<<"\nerasing from handBuffer..."<<(*hiter)<<std::endl;
		  handBuffer.erase(hiter);
		  //add to set here
		  tempCardSet.add(cardTemp);

		  valGrid[i][c1]--;//delete from grid

		}//end if

	    }//end searching in handbuffer (for loop 


	}//end for c1
 

    }//end if multi2!=0

 else if(multi3!=0 &&setCount==3)//have card in 0 2 3 position
    {
          for(int c1=0;c1<=setCount;c1++)
	{
	  Card cardTemp(i+1,c1);
	  bool cardFound=false;

	  for (vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==0;hiter++)
	    {
	      if(c1!=3 && (*hiter)==cardTemp)//dont have card in 0 position
		{
		  cardFound=1;
		  // cout<<"\nerasing from handBuffer..."<<(*hiter)<<std::endl;
		  handBuffer.erase(hiter);
		  //add to set here
		  tempCardSet.add(cardTemp);

		  valGrid[i][c1]--;//delete from grid

		}//end if

	    }//end searching in handbuffer (for loop 


	}//end for c1
 

    }//end if multi3!=0


  // displayHandBuffer(cout);
 // Group tempGroup(tempCardSet);
 cout<<"Computer add a group of "<<setCount<<"cards to table"<<std::endl;
 tb2.push_back(new Group(tempCardSet));
  displayTableBuffer(cout,tb2);
return setExist;

 
  
    }

//return 1 if run exist
bool Computer::lookForRun(vector<Meld*> &tb2)//vector<Meld>
{
  bool runExist=false;
  int runCount=0,i=0,j=0;//keeps track of how many cards are there in a run
  Set<Card> tempCardSet;
  int multi;
  //look up the the 2D table and search for run
  for(j=0;j<4 && runExist==false;j++)//for each suit
    {
      for(i=0;i<=10 && runExist==false;i++)//check from ace to j
	{
	  //if find one run give the starting index
	  //and total number of cards in the run
	   multi=(valGrid[i][j])*(valGrid[i+1][j])*(valGrid[i+2][j]);
	  if(multi!=0)//if 3 in sequence
	    {
	      runExist=true;
	      runCount=3;
	      //cout<<"face starting from: "<<i+1<<" suit:"<<j<< ' ';
	      
	    }	      

	}//end for i
    }//end for j

  if(runCount==0)
    {return runExist;}

  i--;
  j--;//compensate for incrementation
  // cout<<"face starting from: "<<i+1<<" suit:"<<j<< ' ';
  //already found 3-card run, want to find if there is more card
  int tempMulti=1; //keep multiplying
  while((i+runCount)<13 && tempMulti!=0) //total of 13 rows and stop if 
    {
      tempMulti*=valGrid[i+runCount][j];
      if(tempMulti!=0)
	{ 
	  runCount++; 
	}
      

    }//end while


  handBuffer=hand;
  // displayHandBuffer(cout);
  for(int c1=0;c1<runCount;c1++)
    {
      //subtract 1 from the grid
      //look for it in handBuffer and delete,NOTE duplicates!
      Card cardTemp(i+1+c1,j);//i+1+c1 is face, j is value
      bool cardFound=false;//set to false for each card 
      for (vector<Card>::iterator hiter=handBuffer.begin();hiter!=handBuffer.end() && cardFound==0;hiter++)
	{
	  if((*hiter)==cardTemp)
	    {
	      cardFound=1;
	      // cout<<"\nerasing from handBuffer..."<<(*hiter)<<std::endl;
	      handBuffer.erase(hiter);
	      //add to set here
	      tempCardSet.add(cardTemp);

	      valGrid[i+c1][j]--;//delete from grid

	    }

	}//end searching in handbuffer 

    }//end deleting in handbuffer and val Grid and adding in set
  displayHandBuffer(cout);
  //cout<<"Tempcardset:for testing in computer.cpp lookForRun method"<<tempCardSet<<std::endl;//diplay set
  /*
  cout<<"valGrid: for testing in computer.cpp lookForRun method "<<std::endl;//display valGrid here
  for(int i=0;i<13;i++)
    {
    cout<<(i+1)<<' ';
    for(int j=0;j<4;j++)
      { cout<<valGrid[i][j]<< ' ';}

    cout<<'\n';
    }*/
//end display valgrid
  //construct meld here

  // Run tempRun(tempCardSet);
  tb2.push_back(new Run (tempCardSet));
  cout<<"Computer add a new run to table"<<endl;
  displayTableBuffer(cout,tb2);
  //add meld to table buffer

  return runExist;
    

}//end lookForRun

//return 1 if look for run success
bool Computer::firstMove(vector<Meld*> &tb2)
{

  cout<<"computer "<<this->name<<" take 1st move"<<std::endl;
 

  // if(handReadFirst==false)//if not read in 2d array yet
       // {
      readInGrid();
      //  handReadFirst=true;
      // }

  //try to find sequence in the grid 
  //if found set firstMoveDone to 1
  //if not found set firstMoveDone to 0  
  if(lookForRun(tb2)==true)
    {
      firstMoveDone=true;
      // std::cout<<"\nsequence found!"<<std::endl;
      return firstMoveDone;
    }

  else
    {
      firstMoveDone=false;
      /*

 displayHand(cout);
 cout<<"valGrid: for testing in computer.cpp lookForRun method "<<std::endl;//display valGrid here
  for(int i=0;i<13;i++)
    {
    cout<<(i+1)<<' ';
    for(int j=0;j<4;j++)
      { cout<<valGrid[i][j]<< ' ';}

    cout<<'\n';
    }
*/
      std::cout<<"\nrun not found for 1st move,need to draw a card"<<std::endl;
      return firstMoveDone;
    }

  return 0;

}


